/**
 * Copyright 2012 ibiblio
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ibiblio.terasaur.bt

import java.util.Map

import org.ibiblio.terasaur.bt.SeedbankTorrent
import grails.plugins.springsecurity.Secured
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import javax.servlet.http.HttpServletResponse

@Secured(['ROLE_ADMIN', 'IS_AUTHENTICATED_REMEMBERED'])
class SeedbankController {
    static scaffold = true
    static defaultAction = "list"
    boolean _flushTransactions = false // Option for unit testing
    def springSecurityService // injected
    def seedbankService // injected

    def index = {
        redirect(action: "list")
    }

    def list = {
        def listParams = [
            offset: params.offset ? params.int('offset') : 0,
            max: params.max ? Math.min(params.int('max'), 100) : 10
            ]

        def c = Seedbank.createCriteria()
        def results = c.list(listParams) {
        }

        def label = "Seed banks"
        [
            pageTitle: label,
            listLabel: label,
            seedbankList: results,
            seedbankTotal: results.totalCount
        ]
    }

    def show = {
        Seedbank seedbank = Seedbank.get(params.id)
        if (!seedbank) {
            this._setSeedbankNotFound()
            Map m = this._getSeedbankNotFoundMap()
            return m
        }

        String pageTitle = "terasaur: Seed bank details (" + seedbank.name + ")"
        [
            seedbankInstance: seedbank,
            pageTitle: pageTitle,
            canEdit: true
        ]
    }

    def torrents = {
        Seedbank seedbank = Seedbank.get(params.id)
        if (!seedbank) {
            this._setSeedbankNotFound()
            Map m = this._getSeedbankNotFoundMap()
            return m
        }

        // showLinked defaults to true
        boolean showLinked = (params.linked && (params.linked == '0')) ? false : true
        String listLabel = (showLinked) ? "Seeded torrents" : "Unseeded torrents"

        def listParams = [
            offset: params.offset ? params.int('offset') : 0,
            max: params.max ? Math.min(params.int('max'), 100) : 10
            ]

        def c = Torrent.createCriteria()
        def results

        if (showLinked) {
            results = c.list(listParams) {
                seedbanks {
                    eq('seedbank.id', seedbank.id)
                }
                order('name', 'asc')
            }
        } else {
            results = c.list(listParams) {
                seedbanks {
                    isNull('seedbank.id')
                }
                order('name', 'asc')
            }
        }

        String pageTitle = "terasaur: Seed bank torrent list (" + seedbank.name + ")"
        [
            seedbankInstance: seedbank,
            torrentList: results,
            torrentListTotal: results.totalCount,
            showLinked: showLinked,
            pageTitle: pageTitle,
            listLabel: listLabel,
            canEdit: true
        ]
    }

    def create = {
        def map = [
            saveAction : 'create'
            ]
        render(view:"save", model:map)
    }

    def save = {
        Seedbank seedbank = null
        boolean success = false
        try {
            Map result = seedbankService.save(params, springSecurityService.currentUser)
            seedbank = result['seedbank']
            success = result['success']
        } catch (Exception e) {
            log.error("SeedbankService save exception (" + e.class.name + "): " + e.message)
        }

        if (success) {
            redirect(controller:"seedbank", action:"edit", id:seedbank.id)
            flash.message = message(code: 'seedbank.created.message', args:[seedbank.name])
        } else {
            flash.message = "There was a problem saving seed bank information."
        }

        [
            seedbankInstance: seedbank,
            saveAction : 'create'
        ]
    }

    def link = {
        Seedbank seedbank = Seedbank.get(params.id)
        Map redirectParams
        if (!seedbank) {
            flash.message = "Seed bank not found"
            redirectParams = [action:"list"]
        }

        Torrent torrent = Torrent.get(params.info_hash)
        if (!torrent) {
            flash.message = "Torrent not found"
            redirectParams = [action:"torrents", id:seedbank.id]
        }

        if (seedbank && torrent) {
            def st = new SeedbankTorrent(torrent:torrent, seedbank:seedbank)
            if(!st.save(flush:_flushTransactions)) {
                flash.message = "An error occurred seeding torrent " + torrent.name
                def errors = st.errors.getAllErrors()
                errors.each {
                    log.error('SeedbankTorrent link error (' + it.defaultMessage + ')')
                }
            }
            redirectParams = [action:"torrents", id:seedbank.id, params:[linked:'0']]
        }

        redirect(redirectParams)
    }

    def unlink = {
        Seedbank seedbank = Seedbank.get(params.id)
        Map redirectParams
        if (!seedbank) {
            flash.message = "Seed bank not found"
            redirectParams = [action:"list"]
        }

        Torrent torrent = Torrent.get(params.info_hash)
        if (!torrent) {
            flash.message = "Torrent not found"
            redirectParams = [action:"torrents", id:seedbank.id]
        }

        if (seedbank && torrent) {
            def st = SeedbankTorrent.findBySeedbankAndTorrent(seedbank, torrent)
            if (st) {
                try {
                    st.delete(flush:true)
                } catch(org.springframework.dao.DataIntegrityViolationException e) {
                    flash.message = "An error occurred unseeding torrent " + torrent.name
                    log.error("Error unlinking seeded torrent: " + e.message)
                }
            } else {
                flash.message = "Could not find seeded torrent"
            }
            redirectParams = [action:"torrents", id:seedbank.id]
        }

        redirect(redirectParams)
    }

    def delete = {
        Seedbank seedbank = Seedbank.get(params.id)
        def redirectParams
        def okayToDelete = true
        if (!seedbank) {
            flash.message = "Seed bank not found"
            redirectParams = [action:'list']
            okayToDelete = false
        }

        // Can't delete seed bank if there are seeded torrents
        if (seedbank.torrents.size() > 0) {
            flash.message = 'Cannot delete a seed bank that has seeded torrents.  Please unseed all torrents first.'
            redirectParams = [action:'show', id:seedbank.id]
            okayToDelete = false
        }

        if (okayToDelete) {
            try {
                seedbank.delete(flush: true)
                flash.message = message(code: 'seedbank.deleted.message', args: [seedbank.name, seedbank.ipAddress, seedbank.ipPort.toString()])
                redirectParams = [action:'list']
            } catch (Exception e) {
                log.error('Seedbank delete DataIntegrityViolationException', e)
                flash.message = 'There was a problem deleting this seedbank: ' + e.message
                redirectParams = [action:'show', id:seedbank.id]
            }
        }

        redirect(redirectParams)
    }

    /**
     * Helper functions
     */
    protected void _setSeedbankNotFound() {
        response.status = HttpServletResponse.SC_NOT_FOUND
        flash.message = message(code:'seedbank.not.found.message')
    }

    protected Map _getSeedbankNotFoundMap() {
        return [
            pageTitle: "Seed bank not found",
            canEdit: false
            ]
    }

}
